﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using DNBSoft.MSN.ClientController;


namespace WPFMessenger
{
    /// <summary>
    /// Selve logikken der styrer kernen af vores messenger klient. 
    /// </summary>
    public partial class ClientWindow : Window
    {
        #region Konstruktør
        // private delegate void RefreshDelegate();
        MSNController controller = null;
        private delegate void RefreshDelegate();
        //Alle vores brugernavne/kontakter
        private Dictionary<String, ListBoxItem> offlineContactsListItem = new Dictionary<string,ListBoxItem>();
        private Dictionary<String, ListBoxItem> onlineContactsListItem = new Dictionary<string, ListBoxItem>();
        //Den klasse/vindue der håndterer selve samtalen
        private Dictionary<MSNSwitchboard, ConversationWindow> conversationWindows = new Dictionary<MSNSwitchboard, ConversationWindow>(); 
        
        public ClientWindow()
        {   
            Console.WriteLine("started");
            controller = new MSNController();
            InitializeComponent();
            
            //Følgende er events der sættes til at kalde en metode her i klassen.
            //Indtilvidere bruges kun loginstatus changed som kaldes når man enten er logged på eller af
            controller.LoginStatusChanged += new MSNEventDelegates.LoginStatusChangedEventDelegate(controller_LoginStatusChanged);
            controller.FriendlyNameChanged += new MSNEventDelegates.FriendlyNameChangedEventDelegate(controller_FriendlyNameChanged);
            controller.FriendlyNameChanged += new MSNEventDelegates.FriendlyNameChangedEventDelegate(controller_FriendlyNameChanged);
            controller.ContactAdded += new MSNEventDelegates.ContactAddedEventDelegate(controller_ContactAdded);
            controller.SwitchboardController.SwitchboardCreated += new MSNEventDelegates.SwitchboardCreated(SwitchboardController_SwitchboardCreated);
            controller.SwitchboardController.SwitchboardReCreated += new MSNEventDelegates.SwitchboardReCreated(SwitchboardController_SwitchboardReCreated);
            controller.ContactStatusChanged += new MSNEventDelegates.ContactStatusChangedEventDelegate(controller_ContactStatusChanged);
            Console.WriteLine("connnection requested");
        }
        #endregion

        #region Forbindelse til Messenger

        //---------------------------------------------------------------------
        //Denne metode lave selve forbindelsen.
        //---------------------------------------------------------------------
        private void MSNConnect(object sender, RoutedEventArgs e)
        {
            Console.WriteLine("connecting");

            //Såfremt vi alleredee er logget på skal vi logges af (der hænger en forbindelse)
            if (controller.LoginStatus == MSNEnumerations.LoginStatus.LOGGED_IN)
            {
                controller.LoginStatus = MSNEnumerations.LoginStatus.LOGGED_OUT;
                Console.WriteLine("disconnected");

                //Da vi nu er disconnected kan vi forbinde igen. Rekursivt kald.
                MSNConnect(null, null);
            }
            //Hvis vi ikke er forbundet allerede skal der laves en ny forbindelse.
            else if (controller.LoginStatus == MSNEnumerations.LoginStatus.LOGGED_OUT)
            {
                //Brugernavn og password sættes
                controller.Username = tbUsername.Text;
                controller.Password = tbPassword.Text;
                tbFriendlyName.Text = controller.FriendlyName;
                //Login status ændres. Refference bibliotektet ser dette og laver forbindelsen
                controller.LoginStatus = MSNEnumerations.LoginStatus.LOGGED_IN;
                Console.WriteLine("connected");
            }
        }
        //---------------------------------------------------------------------

        //---------------------------------------------------------------------
        //Når der forbindes så ændres login status. Pr default bliver man altid vist som offline
        //---------------------------------------------------------------------
        private void controller_LoginStatusChanged(MSNEnumerations.LoginStatus newStatus)
        {
            this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
                new RefreshDelegate(delegate()
                {
                    //Ens bruger status (online, away, offline etc) skal sættes for at andre kan kontakte en
                    MSNEnumerations.UserStatus userStatus;

                    //Hvis vi er online
                    if (controller.LoginStatus == MSNEnumerations.LoginStatus.LOGGED_IN)
                    {
                        //Bruger status sættes til at være "online"
                        userStatus = MSNEnumerations.UserStatus.online;
                        controller.Status = userStatus;
                        //userStatus = MSNEnumerations.UserStatus.busy;
                        //controller.Status = userStatus;
                        Console.WriteLine("logged in");
                    }
                    else if (controller.LoginStatus == MSNEnumerations.LoginStatus.LOGGED_OUT)
                    {
                        //Logger vi af sættes den til at være offline.
                        userStatus = MSNEnumerations.UserStatus.offline;
                        controller.Status = userStatus;
                        Console.WriteLine("offline");
                    }
                }));
        }
        //---------------------------------------------------------------------
        #endregion

        #region Kontakter og Kontaktlister
        //---------------------------------------------------------------------
        //En kontakt tilføjes. Oftest ved første forbindelse. Kan også ske efterfølgende.
        //---------------------------------------------------------------------
        private void controller_ContactAdded(string username, bool added)
        {
            this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
                new RefreshDelegate(delegate()
                {
                    if (added)
                    {
                        //Vi opretter et nyt item til vores listboxes
                        ListBoxItem lbi = new ListBoxItem();

                        //Username (email) bliver lagt ind som placeholder i content
                        //Det er meningen friendly name skal overskrives her såfremt det bliver sat.
                        lbi.Content = username;
                        //Tooltip bør ikke overskrives med friendly name da email/username skal bruges til at starte en samtale.
                        lbi.ToolTip = username;
                        //Metode der kaldes når der dobbeltklikkes på item i en af listerne.
                        lbi.MouseDoubleClick += new MouseButtonEventHandler(lbi_MouseDoubleClick);
                        //Kontakten tilføjes til offlinelisten samt listbox.
                        offlineContactsListItem.Add(username, lbi);
                        lbOffline.Items.Add(lbi);
                        //Såfremt brugeren ikke er offline ændres dette når deres status modtages.
                    }
                }));
        }
        //---------------------------------------------------------------------

        //---------------------------------------------------------------------
        //Når en kontakt ændrer sin status kaldes denne metode.
        //Det sker som oftest når brugeren logger på. Pr Default er alle brugere offline når de tilføjes som kontakt.
        //---------------------------------------------------------------------
        void controller_ContactStatusChanged(string username, MSNEnumerations.UserStatus status)
        {
            //Vi starter en tråd så systemet ikke står stille
            this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
                new RefreshDelegate(delegate()
                {
                    ListBoxItem lbi;
                    //Item hentes fra offline listen
                    try
                    {
                        lbi = offlineContactsListItem[username];
                    }
                    catch (Exception error)
                    {
                        lbi = onlineContactsListItem[username];
                    }
                    //Hvis brugerens nye status er forskellig fra offline skal han i online listboxen
                    if (status != MSNEnumerations.UserStatus.offline)
                    {
                        try
                        {
                            //Kontakt item fjernes fra offline listen
                            lbOffline.Items.Remove(lbi);
                            offlineContactsListItem.Remove(username);
                            //Og tilføjes til online listen.
                            lbOnline.Items.Add(lbi);
                            onlineContactsListItem.Add(username, lbi);
                        }
                        catch (Exception error)
                        {
                            Console.WriteLine(error);
                        }
                    }
                }));
        }
        //---------------------------------------------------------------------

        //---------------------------------------------------------------------
        //Som default har brugeren ikke noget navn men blot sin email (username)
        //Når brugeren enten skifter eller vi får tilsendt hans friendly name kaldes denne metode
        //---------------------------------------------------------------------
        private void controller_FriendlyNameChanged(string username, string friendlyName)
        {
            this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
                               new RefreshDelegate(delegate()
                               {
                                   //Et beskidt hack her for at sortere imellem offline og online listen
                                   //Failer det når vi forsøger at fjerne den fra offline prøver vi online.
                                   try
                                   {
                                       ListBoxItem lbi = offlineContactsListItem[username];
                                       lbi.Content = friendlyName;
                                   }
                                   catch (Exception error)
                                   {

                                       ListBoxItem lbi = onlineContactsListItem[username];
                                       lbi.Content = friendlyName;
                                   }
                               }));
        }
        //---------------------------------------------------------------------
        #endregion

        #region Samtaler
        //---------------------------------------------------------------------
        //En samtale skal startes når der dobbeltklikkes på en kontakt.
        //---------------------------------------------------------------------
        private void lbi_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            if (controller != null &&
            controller.LoginStatus == MSNEnumerations.LoginStatus.LOGGED_IN)
            {
                //Listbox item indeholder den information vi skal bruge
                ListBoxItem lbi = (ListBoxItem)sender;
                String name = null;

                //Har item et tooltip hentes det ud i name strengen.
                if (lbi.ToolTip != null)
                {
                    //Da friendly name ikke kan bruges til at starte samtalen hentes username ud fra tooltip
                    name = lbi.ToolTip.ToString();
                }
                //Her åbnes der op for muligheden for flere brugeren i samtalen. Pt kun en i listen
                List<String> users = new List<string>();
                users.Add(name);

                //Vi starter samtalen med brugerne i listen.
                controller.startConversation(users);
            }
        }
        //---------------------------------------------------------------------

        //---------------------------------------------------------------------
        //Vi laver et samtale vindue når en samtale startes.
        //---------------------------------------------------------------------
        private void SwitchboardController_SwitchboardCreated(MSNSwitchboard switchboard)
        {
            this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new RefreshDelegate(delegate()
            {
                ConversationWindow window = new ConversationWindow(controller, switchboard);
                conversationWindows.Add(switchboard, window);
                window.Show();
            }));
        }
        //---------------------------------------------------------------------

        //---------------------------------------------------------------------
        //Det gamle samtale vindue genbruges.
        //---------------------------------------------------------------------
        private void SwitchboardController_SwitchboardReCreated(MSNSwitchboard switchboard)
        {
            this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new RefreshDelegate(delegate()
            {
                ConversationWindow window = conversationWindows[switchboard];
                window.Show();
            }));
        }
        //---------------------------------------------------------------------
        #endregion

        #region Andre ting
        //---------------------------------------------------------------------
        //Combo box der gør det muligt for brugeren at ændre sin brugerstatus
        //---------------------------------------------------------------------
        private void statusComboBox_SelectionChanged_1(object sender, SelectionChangedEventArgs e)
        {
            if (statusComboBox.SelectedItem != null &&
          controller != null &&
          controller.LoginStatus == MSNEnumerations.LoginStatus.LOGGED_IN)
            {
                //Da vi skal bruge enumerationer af status skal streng informationen fra comboboxen sammenlignes med enumerationer
                String status = ((ComboBoxItem)(statusComboBox.SelectedItem)).Content.ToString().Trim();
                MSNEnumerations.UserStatus userStatus = MSNEnumerations.UserStatus.online;

                if (status.Equals("Away"))
                {
                    userStatus = MSNEnumerations.UserStatus.away;
                }
                else if (status.Equals("Busy"))
                {
                    userStatus = MSNEnumerations.UserStatus.busy;
                }
                else if (status.Equals("Appear Offline"))
                {
                    userStatus = MSNEnumerations.UserStatus.offline;
                }

                if (controller != null)
                {
                    //Status sættes og opdateres.
                    controller.Status = userStatus;
                }
            }
        }
        //---------------------------------------------------------------------

        //---------------------------------------------------------------------
        //Såfremt brugeren ønsker det kan de ændre deres display navn.
        //---------------------------------------------------------------------
        private void setName_Click(object sender, RoutedEventArgs e)
        {
            //Sættes og opdateres.
            controller.FriendlyName = tbFriendlyName.Text;
        }
        //---------------------------------------------------------------------
        #endregion
    }
}
